home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / QRZ.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-30  |  15.2 KB  |  498 lines

  1. /*
  2.  June 15, 1994 - KF5MG - Jack Snodgrass
  3.  
  4.  This code was adapted/copied from the SAM.C code. The code to process
  5.  the QRZ disk was taken from the QRZ CD-ROM. This code could work
  6.  with the name and zipcode versions of the Callbook data, but as-is, it
  7.  only processes callsigns.
  8. */
  9. #include "global.h"
  10. #ifdef QRZCALLB
  11. #include "ctype.h"
  12.  
  13. #define RECLEN 200
  14. #include "mbuf.h"
  15. #include "socket.h"
  16. #ifndef MSDOS
  17. #include "session.h"
  18. #else
  19. #include "hardware.h"
  20. #endif
  21.  
  22. #if !defined(_lint)
  23. static char rcsid[] OPTIONAL = "$Id: qrz.c,v 1.15 1997/07/31 00:44:20 root Exp root $";
  24. #endif
  25.  
  26. int cb_lookup (int s,char *,FILE *);
  27.  
  28. /* does the actual lookup.   */
  29. static int  qrzfind(char *,int s, FILE *);
  30. /* Parse QRZ data record.    */
  31. static void parse_record(char *, int s);
  32. /* Format QRZ Database Date. */
  33. static void formatdate(char *);
  34. /* Scan a QRZ record for the next field */
  35. static char *scan_field(char *cp, char fieldbuf[], int fieldlen);
  36.  
  37. /* Gobal variables. */
  38. static char pretty_date[12];
  39. static char prettycall[7];
  40. static char *qrzdir = NULLCHAR;
  41. static char *qrzdrv = NULLCHAR;
  42.  
  43. /*     Taken from the QRZ CD-ROM disk.
  44.  *     This block is located at the start of each index
  45.  */
  46. /*
  47.  *     New Index Header Block Definition
  48.  */
  49. typedef struct {
  50.   char  dataname[16];    /* Name of the data file            */
  51.   char  bytesperkey[8];  /* Data Bytes per Index Item        */
  52.   char  numkeys[8];      /* Number of items in this index    */
  53.   char  keylen[8];       /* Length of each key item in bytes */
  54. #ifndef _lint
  55.   char  version[8];      /* Database Version ID              */
  56. #endif
  57. } index_header;
  58.  
  59. /*
  60.  *     Old Index Header Block Definition
  61.  */
  62. typedef struct {
  63. #ifndef _lint
  64.   char  dataname[13];    /* Name of the data file            */
  65. #endif
  66.   long  bytesperkey;     /* Data Bytes per Index Item        */
  67.   int   numkeys;         /* Number of items in this index    */
  68.   int   keylen;          /* Length of each key item in bytes */
  69. } old_index_header;
  70.  
  71. /* return values - 2= Callbook Error 1= not found, 0= okay */
  72. int cb_lookup(s, str, fp)
  73. int s;
  74. char *str;
  75. FILE *fp;
  76. {
  77.    if(qrzfind(str,s,fp)) {
  78.       return 0;
  79.    } else {
  80.       usprintf(s,"\n   No data found for %s.\n", prettycall);
  81.       return 1;
  82.    }
  83. }
  84.  
  85. /*lint -esym(550,numkeys) */
  86. static int qrzfind(char *call_in, int s, FILE *fpout OPTIONAL)
  87. {
  88. index_header     idxhdr;
  89. old_index_header oldidxhdr;
  90.  
  91. FILE         *fp;
  92. char         *buf;
  93. char         *bufptr;
  94. char         IndexFile[] = "callbkc.idx";
  95. int          size;
  96. int          bytesperkey;     /* Data Bytes per Index Item        */
  97. int          numkeys;         /* Number of items in this index    */
  98. int          keylen;          /* Length of each key item in bytes */
  99. int          slots;
  100. int          i,j,k,found,slotcnt;
  101. int          workbufsize;     /* bytesperkey + fudge */
  102. long         fpos;
  103. long         frc;
  104. char         temp[255];
  105. char         call[8];
  106.  
  107.  
  108.    /* call needs to be blank filled. */
  109.    strcpy(call,"       ");
  110.  
  111.    /* Pretty call holds the original, un-qrz-formatted callsign. */
  112.    strcpy(prettycall, call_in);
  113.    (void) strupr(prettycall);
  114.  
  115.  
  116.    k = (int) strlen(call_in);
  117.    if (k>6) {
  118.       usprintf(s,"Callsign too long.\n");
  119.       return 0;
  120.    }
  121.  
  122.    /* Callsigns in the QRZ Index are stored in a weird format. They are */
  123.    /* 6 characters in length ( padded with spaces ), in the format of   */
  124.    /* ccdccc where the digit is always in the 3rd posistion. If the     */
  125.    /* callsign is a 1-by-something callsign, the 2nd posistion will be  */
  126.    /* blank. KF5MG will be stored as KF5MGb. N5VGC will be stored as    */
  127.    /* Nb5VGC. ( the b are spaces )                                      */
  128.    /*                                                                   */
  129.    call[0] = call_in[0];
  130.    i = j = 1;
  131.    if(!isdigit(call_in[j]))
  132.       call[i++] = call_in[j++];
  133.    else
  134.       call[i++] = ' ';
  135.    if(isdigit(call_in[j])) {
  136.       call[i++] = call_in[j++];
  137.    } else {
  138.       /* No digit found in position 2 or 3. */
  139.       usprintf(s,"Error parsing callsign... %s\n", call_in);
  140.       return 0;
  141.    }
  142.    for ( ; j < (int)strlen(call_in); j++)
  143.       call[i++] = call_in[j];
  144.    call[6]=0;
  145.    (void) strupr(call);
  146.  
  147.  
  148.    /* Get path info. Use defaults if not available. */
  149.    if (qrzdir == NULLCHAR) {
  150.       if((qrzdir = getenv("QRZPATH")) == NULLCHAR) {
  151.          #ifdef UNIX
  152.          qrzdir =  strdup("/callbk");
  153.          #else
  154.          qrzdir =  strdup("\\callbk");
  155.          #endif
  156.       }
  157.    } /* endif */
  158.    if (qrzdrv == NULLCHAR) {
  159.       if((qrzdrv = getenv("QRZDRV")) == NULLCHAR) {
  160.          #ifdef UNIX
  161.          qrzdrv =  strdup("/nos");
  162.          #else
  163.          qrzdrv =  strdup("D:");
  164.          #endif
  165.       }
  166.    } /* endif */
  167.  
  168.    /* Open the index file.  We'll use it to tell us the name of the     */
  169.    /* database file. We'll also find the database version and some      */
  170.    /* other useful info.                                                */
  171.    /*                                                                   */
  172.    #ifdef UNIX
  173.    sprintf(temp,"%s%s/%s",qrzdrv,qrzdir,IndexFile);
  174.    #else
  175.    sprintf(temp,"%s%s\\%s",qrzdrv,qrzdir,IndexFile);
  176.    #endif
  177.    if((fp = fopen(temp,"rt"))==NULLFILE) {
  178.       usprintf(s,"Error opening Index: %s\n",temp);
  179.       return 0;
  180.    }
  181.  
  182.    size = (int) fread(&idxhdr,sizeof(idxhdr),1,fp);
  183.    if(size != 1) {
  184.       usprintf(s,"Error reading Index Header.\n");
  185.       (void) fclose(fp);
  186.       return 0;
  187.    }
  188.  
  189.    /* Old Style Index has a '0' at pos 16 and 17. - this is SUPPOSE to be valid !?!? */
  190.    if((int)idxhdr.dataname[16] != 0) {        /*lint !e415 */
  191.       /* This is a 'new' style index */
  192.       bytesperkey = atoi(idxhdr.bytesperkey);   /* size of data area.   */
  193.       numkeys     = atoi(idxhdr.numkeys);       /* # of keys in file.   */
  194.       keylen      = atoi(idxhdr.keylen);        /* length of each key.  */
  195.    } else {
  196.       /* This is an 'old' style index.                                          */
  197.       /* rewind the file and read the header using the old_index_header struct. */
  198.       rewind(fp);
  199.  
  200.       size = (int) fread(&oldidxhdr,sizeof(oldidxhdr),1,fp);
  201.       if(size != 1) {
  202.          usprintf(s,"Error reading Index Header.\n");
  203.          (void) fclose(fp);
  204.          return 0;
  205.       }
  206.       bytesperkey = (int)oldidxhdr.bytesperkey; /* size of data area.   */
  207.       numkeys     = oldidxhdr.numkeys;          /* # of keys in file.   */
  208.       keylen      = oldidxhdr.keylen;           /* length of each key.  */
  209.    }
  210.  
  211.    /* This is a 10K ish buffer. Each 'key' in the index covers almost   */
  212.    /* 10K of data. Once you find the correct key, you have to read the  */
  213.    /* 10K chunk of data from the data file. You then start searching    */
  214.    /* for the correct callsign. This code uses the same 10k buffer to   */
  215.    /* scan the index file ( typically 40K so you might do 4 reads ) to  */
  216.    /* save memory. Once you've found the correct key, you calculate the */
  217.    /* offset into the database. You then read the data base into your   */
  218.    /* 10K buffer.  (We fudge bytesperkey by RECLEN to avoid a truncated */
  219.    /* last record in the buffer).                                       */
  220.    /*                                                                   */
  221.    workbufsize = bytesperkey+RECLEN;
  222.    bufptr      = mallocw((unsigned) workbufsize);           /* Get space for buffer */
  223.    if (bufptr == NULL) {     /* no space */
  224.       usprintf(s,"No space for %d byte buffer.\n",workbufsize);
  225.       (void) fclose(fp);
  226.       return(0);
  227.    }
  228.  
  229.    slots       = bytesperkey / keylen;          /* Calculate # of slots */
  230.    found       = 0;
  231.    slotcnt     = 0;
  232.  
  233.    do {
  234.       /* Point floating buf pointer to start of big buffer.   */
  235.       buf      = bufptr;
  236.       /* Read slots number of entries that are keylen in size */
  237.       size = (int) fread(buf,(unsigned) keylen, (unsigned) slots,fp);
  238.       if(size == 0) {
  239.          usprintf(s,"Error reading Index file.\n");
  240.          found = 2;
  241.       }
  242.  
  243.       /* Start scanning Index buffer. If the data is less than your search */
  244.       /* Value... keep going. If the Data is greater, then your done. You  */
  245.       /* then subtract one from your slotcnt (unless it's an exact match)  */
  246.       /* and that's the closet record to your data.                        */
  247.       /*                                                                   */
  248.       for(i=0;i<size;i++) {
  249.         slotcnt++;
  250.         strncpy(temp,(char *)buf, (unsigned) keylen);
  251.         temp[keylen] = 0;
  252.         if(strncmp(&temp[3],&call[3],3) >= 0) {
  253.            if(strncmp(&temp[3],&call[3],3) > 0) {
  254.               found = 1;
  255.               slotcnt--;
  256.            }
  257.            else {  /* last 3 equal. How about digit? */
  258.               if(strncmp(&temp[2],&call[2],1) >= 0) {
  259.                  if(strncmp(&temp[2],&call[2],1) > 0) {
  260.                     slotcnt--;
  261.                     found = 1;
  262.                  }
  263.                  else /* digits are equal. Check first 2 chars */
  264.                     if(strncmp(&temp[0],&call[0],2) > 0) {
  265.                        slotcnt--;
  266.                        found = 1;
  267.                     }
  268.               }
  269.            }
  270.         }
  271.         if(found)
  272.            break;
  273.         buf += keylen;
  274.       }
  275.    } while(!found); /* enddo */
  276.  
  277.    slotcnt--;
  278.  
  279.    /* We're done with the Index so we can close it. */
  280.    (void) fclose(fp);
  281.  
  282.    /* If we found a match, the calculate the offset and read the data. */
  283.    if(found == 1) {
  284.       buf      = bufptr;
  285.       #ifdef UNIX
  286.       sprintf(temp,"%s%s/%s",qrzdrv,qrzdir,idxhdr.dataname);
  287.       #else
  288.       sprintf(temp,"%s%s\\%s",qrzdrv,qrzdir,idxhdr.dataname);
  289.       #endif
  290.       if((fp = fopen(temp,"rt"))==NULLFILE) {
  291.          usprintf(s,"Error opening Database: %s\n",temp);
  292.          free(bufptr);
  293.          return 0;
  294.       }
  295.  
  296.       /* seek to correct posistion in file .                           */
  297.       fpos = (long) bytesperkey*slotcnt;
  298.  
  299.       frc = lseek(fileno(fp),(long) fpos,SEEK_SET);
  300.       if(frc < 0L) {
  301.          usprintf(s,"Error seeking Database file.\n");
  302.          free(bufptr);
  303.          (void) fclose(fp);
  304.          return 0;
  305.       }
  306.  
  307.       /* Read slot from callbk file. */
  308.       size = (int) fread(buf, (unsigned) workbufsize,1,fp);
  309.       if(size < 1) {
  310.          usprintf(s,"Error reading Database file.\n");
  311.          free(bufptr);
  312.          (void) fclose(fp);
  313.          return 0;
  314.       }
  315.  
  316.       /* Done with data file. Now we can close it too. Our target is either */
  317.       /* in our buffer or doesn't exist.                                   */
  318.       (void) fclose(fp);
  319.  
  320.       i = 0;
  321.       for(;;) {
  322.          if(i>workbufsize) {
  323.             found = 0;
  324.             break;
  325.          }
  326.          k = (int) strcspn(buf,"\n");
  327.          if(k == 0) {
  328.             found = 0;
  329.             break;
  330.          }
  331.          strncpy(temp,buf, (unsigned) k);
  332.          temp[k] = 0;
  333.          for(j=0;j<=k;j++)
  334.             buf += 1;
  335.  
  336.          /* Find our user. */
  337.          if(strncmp(temp,call,6) == 0) {
  338.             /* Found it. Now read and format the data. */
  339.             parse_record(temp,s);
  340.             break;
  341.          }
  342.          i+=k;
  343.       }
  344.    }
  345.    /* Done with the buffer. */
  346.    free(bufptr);
  347.    return found;
  348. }
  349.  
  350. static char *
  351. scan_field(char *cp, char fieldbuf[], int fieldlen)
  352. {
  353.   char *cp1;
  354.  
  355.   cp1 = strchr(cp, ',');
  356.   if (cp1) {
  357.      *cp1++ = 0;
  358.      strncpy(fieldbuf, cp, (unsigned) fieldlen);
  359.      fieldbuf[fieldlen-1] = 0;
  360.      cp=cp1;
  361.   }
  362.   else fieldbuf[0]=0;
  363.   return(cp);
  364. }
  365.  
  366. static void parse_record(char *record, int s) {
  367. /*
  368.  *    Standard Record Format
  369.  */
  370. char callsign[7];         /* Call Sign Decoded      */
  371. char lastname[33];        /* Last Name              */
  372. char namesuffix[3];       /* Name Suffix            */
  373. char frstname[33];        /* First Name             */
  374. char middleinit[3];       /* Middle Initial         */
  375. char datelicensed[6];     /* Date Licensed mm/dd/yy */
  376. char dateborn[6];         /* Date Born              */
  377. char dateexpires[6];         /* Date Born              */
  378. char streetaddr[33];      /* Street Address         */
  379. char city[33];            /* City                   */
  380. char state[3];            /* State Code             */
  381. char zipcode[6];          /* Zip Code               */
  382. char license_class[3];    /* License Class          */
  383. char prevcall[7];         /* Previous Call          */
  384. char prevclass[3];        /* Previous Class         */
  385.  
  386. char *cp;
  387. char fullname[80];
  388. char address[80];
  389. char temp2[255];
  390.  
  391. int  rc;
  392.  
  393. #ifdef QRZDEBUG
  394.   usprintf(s, "debug: %s\n", record);
  395. #endif
  396.   strcpy(temp2,record);
  397.   cp=temp2;
  398.   cp = scan_field(cp, callsign, sizeof(callsign));
  399.  
  400.   if(strlen(record) < 16) {
  401.      usprintf(s,"%s is an old call for %s\n", prettycall, cp);
  402.      rc =  cb_lookup(s,cp,(FILE *) 0);
  403.      if(rc != 0)
  404.         usprintf(s,"no info found for %s.\n", cp);
  405.      return;
  406.   }
  407.  
  408.   cp = scan_field(cp, lastname, sizeof(lastname));
  409.  
  410.   cp = scan_field(cp, namesuffix, sizeof(namesuffix));
  411.  
  412.   cp = scan_field(cp, frstname, sizeof(frstname));
  413.  
  414.   cp = scan_field(cp, middleinit, sizeof(middleinit));
  415.  
  416.   cp = scan_field(cp, dateborn, sizeof(dateborn));
  417.  
  418.   cp = scan_field(cp, datelicensed, sizeof(datelicensed));
  419.  
  420.   cp = scan_field(cp, dateexpires, sizeof(dateexpires));
  421.  
  422.   cp = scan_field(cp, streetaddr, sizeof(streetaddr));
  423.  
  424.   cp = scan_field(cp, city, sizeof(city));
  425.  
  426.   cp = scan_field(cp, state, sizeof(state));
  427.  
  428.   cp = scan_field(cp, zipcode, sizeof(zipcode));
  429.  
  430.   cp = scan_field(cp, license_class, sizeof(license_class));
  431.  
  432.   cp = scan_field(cp, prevcall, sizeof(prevcall));
  433.  
  434.   cp = scan_field(cp, prevclass, sizeof(prevclass));
  435.  
  436.   sprintf(fullname,"%s%s%s%s%s%s%s",frstname, middleinit[0] == 0 ? "":" ",middleinit,
  437.       middleinit[0] == 0 ? " ":". ", lastname, namesuffix[0] == 0 ? " ":", ", namesuffix);
  438.   sprintf(address, "%s, %s, %s", city, state, zipcode);
  439.  
  440.   usprintf(s,"\n%-8s", prettycall);
  441.   usprintf(s,"%-45s", fullname);
  442.   formatdate(dateborn);
  443.   usprintf(s,"Born:    %s\n", pretty_date);
  444.  
  445.   usprintf(s,"%-8s%-45s","", streetaddr);
  446.   formatdate(datelicensed);
  447.   usprintf(s,"Class: %s %s\n", (license_class[0]?license_class:"r"), pretty_date);
  448.  
  449.   usprintf(s,"%-8s%-45s", "", address);
  450.   usprintf(s,"Prev:  %s %s\n", prevclass, prevcall);
  451.  
  452.   formatdate(dateexpires);
  453.   usprintf(s,"%52s Expir:   %s\n", "", pretty_date);
  454.  
  455.   return;
  456. }
  457.  
  458. static void formatdate(char *date){
  459. char year[5];
  460. char rest[4];
  461. int  mon = 0;
  462. int  day = 0;
  463. int  days;
  464. int  years;
  465. int  i;
  466.  
  467. int  dayarray[13] = { 0, 31,  60,  91, 121, 152, 182,  /* 0 permits handling 00000 better */
  468.                      213, 244, 274, 305, 335, 366 };
  469.  
  470.    strncpy(year,date,2);
  471.    year[2]  = 0;
  472.    years    = atoi(year);
  473. #ifdef notdef
  474.    if(years < 20)   /* fails for DOB, where 15 => 1915. -- n5knx */
  475.       years += 2000;
  476.    else
  477.       years += 1900;
  478. #endif
  479.  
  480.    strncpy(rest,&date[2],3);
  481.    rest[3]  = 0;
  482.    days     = atoi(rest);
  483.  
  484.    if((years % 4) != 0)   /* fails in 2100 */
  485.       if(days > 59)
  486.          days++;
  487.  
  488.    for(i=1;i<13;i++){
  489.       if(days <= dayarray[i]) {
  490.          mon = i;
  491.          day = days - dayarray[i-1];
  492.          break;
  493.       }
  494.    }
  495.    sprintf(pretty_date, "%02d/%02d/%02d", mon,day,years);
  496. }
  497. #endif
  498.